<html><head><meta charset="utf-8"><title>14 简化工作：Guava Lists Maps 实际工作运用和源码-慕课专栏</title>
			<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
			<meta name="renderer" content="webkit">
			<meta property="qc:admins" content="77103107776157736375">
			<meta property="wb:webmaster" content="c4f857219bfae3cb">
			<meta http-equiv="Access-Control-Allow-Origin" content="*">
			<meta http-equiv="Cache-Control" content="no-transform ">
			<meta http-equiv="Cache-Control" content="no-siteapp">
			<link rel="apple-touch-icon" sizes="76x76" href="https://www.imooc.com/static/img/common/touch-icon-ipad.png">
			<link rel="apple-touch-icon" sizes="120x120" href="https://www.imooc.com/static/img/common/touch-icon-iphone-retina.png">
			<link rel="apple-touch-icon" sizes="152x152" href="https://www.imooc.com/static/img/common/touch-icon-ipad-retina.png">
			<link href="https://moco.imooc.com/captcha/style/captcha.min.css" rel="stylesheet">
			<link rel="stylesheet" href="https://www.imooc.com/static/moco/v1.0/dist/css/moco.min.css?t=201907021539" type="text/css">
			<link rel="stylesheet" href="https://www.imooc.com/static/lib/swiper/swiper-3.4.2.min.css?t=201907021539">
			<link rel="stylesheet" href="https://static.mukewang.com/static/css/??base.css,common/common-less.css?t=2.5,column/zhuanlanChapter-less.css?t=2.5,course/inc/course_tipoff-less.css?t=2.5?v=201907051055" type="text/css">
			<link charset="utf-8" rel="stylesheet" href="https://www.imooc.com/static/lib/ueditor/themes/imooc/css/ueditor.css?v=201907021539"><link rel="stylesheet" href="https://www.imooc.com/static/lib/baiduShare/api/css/share_style0_16.css?v=6aba13f0.css"></head>
			<body><div id="main">


<div class="main-con hide-menu">
    <!-- 左侧菜单 & 索引 -->
    
    <div class="right-content" style="padding-left: 0px;">
        <div class="container clearfix" id="top" style="width: 1134px; display: block;">
            
            
            <div class="center_con js-center_con l" style="width: 1134px;">
                <div class="article-con">
                                            <!-- 买过的阅读 -->
                        

                    
                    <div class="art-title" style="margin-top: 0px;">
                        14 简化工作：Guava Lists Maps 实际工作运用和源码
                    </div>
                    <div class="art-info clearfix">
                        
                        <span class="l">
                            更新时间：2019-09-24 10:32:00
                        </span>
                    </div>
                    <div class="art-top">
                                                <img src="https://img4.mukewang.com/5d80435b0001bcad06400359.jpg" alt="">
                                                                        <div class="famous-word-box">
                            <img src="https://www.imooc.com/static/img/column/bg-l.png" alt="" class="bg1 bg">
                            <img src="https://www.imooc.com/static/img/column/bg-r.png" alt="" class="bg2 bg">
                            <div class="famous-word">如果不想在世界上虚度一生，那就要学习一辈子。<p class="author">——高尔基</p></div>
                        </div>
                                            </div>
                    <div class="art-content js-lookimg">
                        <div id="article_content">
                            <div class="cl-preview-section"><h2 id="引导语" style="font-size: 30px;">引导语</h2>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">在日常工作中，我们经常会使用一些三方的 API 来简化我们的工作，Guava 就是其中一种，Guava 是 Google 开源的技术框架，使用率高，社区活跃度也很高。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">本小节我们从工作中对  Guava 集合的使用入手，然后深入的看下其底层的实现，最后总结其设计思想，感兴趣的同学也可以下载源码学习，GitHub 地址：<a href="https://github.com/google/guava%EF%BC%8C%E6%BA%90%E7%A0%81%E4%B8%AD">https://github.com/google/guava，源码中</a> guava 的文件夹为其源码。</p>
</div><div class="cl-preview-section"><h2 id="运用工厂模式进行初始化" style="font-size: 30px;">1 运用工厂模式进行初始化</h2>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">在集合类初始化方面，Guava 比 Java 原生的 API 更加好用，还发明了很多新的功能，比如说在 JDK 7 之前，我们新建集合类时，声明和初始化都必须写上泛型说明，像这样：<code>List&lt;泛型&gt; list = new ArrayList&lt;泛型&gt;();</code> ， JDK 7 之后有所改变，我们只需要在声明处写上泛型说明，像这样：<code>List&lt;泛型&gt; list = new ArrayList&lt;&gt;();</code>。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">Guava 提供了更加方便的使用姿势，采用了工厂模式，把集合创建的逻辑交给了工厂，开发者无需关注工厂底层是如何创建的，只需要关心，工厂能产生什么，代码于是变成了这样：<code>List&lt;泛型&gt; list = Lists.newArrayList();</code>，Lists 就是 Guava 提供出来的，方便操作 List 的工具类。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">这种写法其实就是一种简单的工厂模式，只需要定义好工厂的入参和出参，就能对外隐藏其内部的创建逻辑，提供更加方便的使用体验。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">当然除了 Lists，Guava 还提供了很多其他实用工具，如  Maps、Sets，接下来我们分别来看下这些常用工具的使用和原理。</p>
</div><div class="cl-preview-section"><h2 id="lists" style="font-size: 30px;">2 Lists</h2>
</div><div class="cl-preview-section"><h3 id="初始化">2.1 初始化</h3>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">Lists 最大的功能是能帮助我们进行 List 的初始化，比如我们刚说的 newArrayList 这种：</p>
</div><div class="cl-preview-section"><pre class="  language-java"><code class="prism  language-java">List<span class="token operator">&lt;</span>String<span class="token operator">&gt;</span> list <span class="token operator">=</span> Lists<span class="token punctuation">.</span><span class="token function">newArrayList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token operator">&lt;</span>E<span class="token operator">&gt;</span> ArrayList<span class="token operator">&lt;</span>E<span class="token operator">&gt;</span> <span class="token function">newArrayList</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token operator">&lt;</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// 这种底层是帮助我们写好了泛型，E 代表泛型，表示当前返回的泛型类型和声明的一致即可，在编译的时候，会把泛型 E 转化成我们声明的 String。</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">如果你清楚 List 的大小，我们也可以这样做：</p>
</div><div class="cl-preview-section"><pre class="  language-java"><code class="prism  language-java"><span class="token comment">// 可以预估 list 的大小为 20</span>
List<span class="token operator">&lt;</span>String<span class="token operator">&gt;</span> list <span class="token operator">=</span> Lists<span class="token punctuation">.</span><span class="token function">newArrayListWithCapacity</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 不太肯定 list 大小是多少，但期望是大小是 20 上下。</span>
List<span class="token operator">&lt;</span>String<span class="token operator">&gt;</span> list <span class="token operator">=</span> Lists<span class="token punctuation">.</span><span class="token function">newArrayListWithExpectedSize</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">newArrayListWithCapacity(20) 方法内部实现是：<code>new ArrayList&lt;&gt;(20);</code>，而 newArrayListWithExpectedSize  方法内部实现是对 List 大小有一个计算公式的，计算公式为：<code>5L + arraySize + (arraySize / 10)</code> ，arraySize 表示传进来的值，公式简化下就是 5 + 11/10 * arraySize，因为这个方法表示期望的大小，所以这里取的约是期望值的十分之十一，比传进来的值约大十分之一，所以根据 20 最终计算出来的值是 27。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">Lists 在初始化的时候，还支持传迭代器的入参（只适合小数据量的迭代器的入参），源码如下：</p>
</div><div class="cl-preview-section"><pre class="  language-java"><code class="prism  language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token operator">&lt;</span>E<span class="token operator">&gt;</span> ArrayList<span class="token operator">&lt;</span>E<span class="token operator">&gt;</span> <span class="token function">newArrayList</span><span class="token punctuation">(</span>Iterator<span class="token operator">&lt;</span><span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">E</span><span class="token operator">&gt;</span> elements<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  ArrayList<span class="token operator">&lt;</span>E<span class="token operator">&gt;</span> list <span class="token operator">=</span> <span class="token function">newArrayList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">// addAll 方法底层其实通过迭代器进行 for 循环添加</span>
  Iterators<span class="token punctuation">.</span><span class="token function">addAll</span><span class="token punctuation">(</span>list<span class="token punctuation">,</span> elements<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> list<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">从 Lists 对 List 初始化进行包装的底层源码来看，底层源码非常简单的，但我们还是愿意使用这种方式的包装，主要是因为这种工厂模式的包装，使我们的使用姿势更加优雅，使用起来更加方便。</p>
</div><div class="cl-preview-section"><h3 id="分组和反转排序">2.2 分组和反转排序</h3>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">除了初始化之外，Lists 还提供了两个比较实用的功能，分组和反转排序功能，我们分别来演示一下：</p>
</div><div class="cl-preview-section"><pre class="  language-java"><code class="prism  language-java"><span class="token comment">// 演示反转排序</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testReverse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  List<span class="token operator">&lt;</span>String<span class="token operator">&gt;</span> list <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token operator">&lt;</span>String<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">{</span>
    <span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"10"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"20"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"30"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"40"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
  log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"反转之前："</span><span class="token operator">+</span>JSON<span class="token punctuation">.</span><span class="token function">toJSONString</span><span class="token punctuation">(</span>list<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  list <span class="token operator">=</span> Lists<span class="token punctuation">.</span><span class="token function">reverse</span><span class="token punctuation">(</span>list<span class="token punctuation">)</span><span class="token punctuation">;</span>
  log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"反转之后："</span><span class="token operator">+</span>JSON<span class="token punctuation">.</span><span class="token function">toJSONString</span><span class="token punctuation">(</span>list<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// 打印出来的结果为：</span>
反转之前：<span class="token punctuation">[</span><span class="token string">"10"</span><span class="token punctuation">,</span><span class="token string">"20"</span><span class="token punctuation">,</span><span class="token string">"30"</span><span class="token punctuation">,</span><span class="token string">"40"</span><span class="token punctuation">]</span>
反转之后：<span class="token punctuation">[</span><span class="token string">"40"</span><span class="token punctuation">,</span><span class="token string">"30"</span><span class="token punctuation">,</span><span class="token string">"20"</span><span class="token punctuation">,</span><span class="token string">"10"</span><span class="token punctuation">]</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">reverse 方法底层实现非常巧妙，底层覆写了 List 原生的 get(index) 方法，会把传进来的 index 进行 (size - 1) - index 的计算，使计算得到的索引位置和 index 位置正好相反，这样当我们 get 时，数组索引位置的 index 已经是相反的位置了，达到了反转排序的效果，其实底层并没有进行反转排序，只是在计算相反的索引位置，通过计算相反的索引位置这样简单的设计，得到了反转排序的效果，很精妙。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">在工作中，有时候我们需要把一个大的 list 进行切分，然后再把每份丢给线程池去运行，最后将每份运行的结果汇总，Lists 工具类就提供了一个对 list 进行切分分组的方法，演示 demo 如下：</p>
</div><div class="cl-preview-section"><pre class="  language-java"><code class="prism  language-java"><span class="token comment">// 分组</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testPartition</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  List<span class="token operator">&lt;</span>String<span class="token operator">&gt;</span> list <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token operator">&lt;</span>String<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">{</span>
    <span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"10"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"20"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"30"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"40"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
  log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"分组之前："</span><span class="token operator">+</span>JSON<span class="token punctuation">.</span><span class="token function">toJSONString</span><span class="token punctuation">(</span>list<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   List<span class="token operator">&lt;</span>List<span class="token operator">&lt;</span>String<span class="token operator">&gt;&gt;</span> list2 <span class="token operator">=</span> Lists<span class="token punctuation">.</span><span class="token function">partition</span><span class="token punctuation">(</span>list<span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"分组之后："</span><span class="token operator">+</span>JSON<span class="token punctuation">.</span><span class="token function">toJSONString</span><span class="token punctuation">(</span>list2<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
输出结果为：
分组之前：<span class="token punctuation">[</span><span class="token string">"10"</span><span class="token punctuation">,</span><span class="token string">"20"</span><span class="token punctuation">,</span><span class="token string">"30"</span><span class="token punctuation">,</span><span class="token string">"40"</span><span class="token punctuation">]</span>
分组之后：<span class="token punctuation">[</span><span class="token punctuation">[</span><span class="token string">"10"</span><span class="token punctuation">,</span><span class="token string">"20"</span><span class="token punctuation">,</span><span class="token string">"30"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token punctuation">[</span><span class="token string">"40"</span><span class="token punctuation">]</span><span class="token punctuation">]</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">partition 方法的第二个参数的意思，你想让分组后的 List 包含几个元素，这个方法的底层实现其实就是 subList 方法。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">有一点需要我们注意的是这两个方法返回的 List 并不是 ArrayList，是自定义的 List，所以对于 ArrayList 的有些功能可能并不支持，使用的时候最好能看下源码，看看底层有无支持。</p>
</div><div class="cl-preview-section"><h3 id="小结">2.3 小结</h3>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">Lists 上述的方法大大的方便了我们进行开发，简化了使用姿势，但其内部实现却非常简单巧妙，比如说 reverse 方法可以输出相反排序的 List，但底层并没有实现排序，只是计算了索引位置的相反值而已，这点值得我们学习。</p>
</div><div class="cl-preview-section"><h2 id="maps" style="font-size: 30px;">3 Maps</h2>
</div><div class="cl-preview-section"><h3 id="初始化-1">3.1 初始化</h3>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">Maps 也是有着各种初始化 Map 的各种方法，原理不说了，和 Lists 类似，我们演示下如何使用：</p>
</div><div class="cl-preview-section"><pre class="  language-java"><code class="prism  language-java">Map<span class="token operator">&lt;</span>String<span class="token punctuation">,</span>String<span class="token operator">&gt;</span> hashMap <span class="token operator">=</span> Maps<span class="token punctuation">.</span><span class="token function">newHashMap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Map<span class="token operator">&lt;</span>String<span class="token punctuation">,</span>String<span class="token operator">&gt;</span> linkedHashMap <span class="token operator">=</span> Maps<span class="token punctuation">.</span><span class="token function">newLinkedHashMap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 这里 Map 的初始化大小公式和 HashSet 初始化公式类似，还记得 HashSet 初始化 HashMap 时，经典的计算初始大小的公式么：取最大值（期望的值 / 0.75 + 1，默认值 16），newHashMapWithExpectedSize 方法底层也是这么算的初始化大小的</span>
Map<span class="token operator">&lt;</span>String<span class="token punctuation">,</span>String<span class="token operator">&gt;</span> withExpectedSizeHashMap <span class="token operator">=</span> Maps<span class="token punctuation">.</span><span class="token function">newHashMapWithExpectedSize</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
</div><div class="cl-preview-section"><h3 id="difference">3.2 difference</h3>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">Maps 提供了一个特别有趣也很实用的方法：difference，此方法的目的是比较两个 Map 的差异，入参就是两个 Map，比较之后能够返回四种差异：</p>
</div><div class="cl-preview-section"><ol>
<li style="font-size: 20px; line-height: 38px;">左边 Map 独有 key。</li>
<li style="font-size: 20px; line-height: 38px;">右边 Map 独有 key。</li>
<li style="font-size: 20px; line-height: 38px;">左右边 Map 都有 key，并且 value 相等。</li>
<li style="font-size: 20px; line-height: 38px;">左右边 Map 都有 key，但是 value 不等。</li>
</ol>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">我们用代码来演示一下：</p>
</div><div class="cl-preview-section"><pre class="  language-java"><code class="prism  language-java"><span class="token comment">// ImmutableMap.of 也是 Guava 提供初始化 Map 的方法，入参格式为 k1,v1,k2,v2,k3,v3……</span>
Map<span class="token operator">&lt;</span>String<span class="token punctuation">,</span>String<span class="token operator">&gt;</span> leftMap <span class="token operator">=</span> ImmutableMap<span class="token punctuation">.</span><span class="token function">of</span><span class="token punctuation">(</span><span class="token string">"1"</span><span class="token punctuation">,</span><span class="token string">"1"</span><span class="token punctuation">,</span><span class="token string">"2"</span><span class="token punctuation">,</span><span class="token string">"2"</span><span class="token punctuation">,</span><span class="token string">"3"</span><span class="token punctuation">,</span><span class="token string">"3"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Map<span class="token operator">&lt;</span>String<span class="token punctuation">,</span>String<span class="token operator">&gt;</span> rightMap <span class="token operator">=</span> ImmutableMap<span class="token punctuation">.</span><span class="token function">of</span><span class="token punctuation">(</span><span class="token string">"2"</span><span class="token punctuation">,</span><span class="token string">"2"</span><span class="token punctuation">,</span><span class="token string">"3"</span><span class="token punctuation">,</span><span class="token string">"30"</span><span class="token punctuation">,</span><span class="token string">"4"</span><span class="token punctuation">,</span><span class="token string">"4"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
MapDifference difference <span class="token operator">=</span> Maps<span class="token punctuation">.</span><span class="token function">difference</span><span class="token punctuation">(</span>leftMap<span class="token punctuation">,</span> rightMap<span class="token punctuation">)</span><span class="token punctuation">;</span>
log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"左边 map 独有 key：{}"</span><span class="token punctuation">,</span>difference<span class="token punctuation">.</span><span class="token function">entriesOnlyOnLeft</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"右边 map 独有 key：{}"</span><span class="token punctuation">,</span>difference<span class="token punctuation">.</span><span class="token function">entriesOnlyOnRight</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"左右边 map 都有 key，并且 value 相等：{}"</span><span class="token punctuation">,</span>difference<span class="token punctuation">.</span><span class="token function">entriesInCommon</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"左右边 map 都有 key，但 value 不等：{}"</span><span class="token punctuation">,</span>difference<span class="token punctuation">.</span><span class="token function">entriesDiffering</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
最后打印结果为：
左边 map 独有 key：<span class="token punctuation">{</span><span class="token number">1</span><span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">}</span>
右边 map 独有 key：<span class="token punctuation">{</span><span class="token number">4</span><span class="token operator">=</span><span class="token number">4</span><span class="token punctuation">}</span>
左右边 map 都有 key，并且 value 相等：<span class="token punctuation">{</span><span class="token number">2</span><span class="token operator">=</span><span class="token number">2</span><span class="token punctuation">}</span>
左右边 map 都有 key，但 value 不等：<span class="token punctuation">{</span><span class="token number">3</span><span class="token operator">=</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">30</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">从这个 demo 我们可以看到此方法的强大威力，我们在工作中经常遇到 Map 或者 List 间比较差异的任务，我们就可以直接使用该方法进行对比，List 可以先转化成 Map。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">而且 difference 底层的实现也算是最优的实现了，只需要循环一遍，就可得到上述四种差异结果，源码解析如下：</p>
</div><div class="cl-preview-section"><pre class="  language-java"><code class="prism  language-java"><span class="token comment">// 对比两个 map 的差异</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token operator">&lt;</span>K<span class="token punctuation">,</span> V<span class="token operator">&gt;</span> <span class="token keyword">void</span> <span class="token function">doDifference</span><span class="token punctuation">(</span>
    Map<span class="token operator">&lt;</span><span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">K</span><span class="token punctuation">,</span> <span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">V</span><span class="token operator">&gt;</span> left<span class="token punctuation">,</span>
    Map<span class="token operator">&lt;</span><span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">K</span><span class="token punctuation">,</span> <span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">V</span><span class="token operator">&gt;</span> right<span class="token punctuation">,</span>
    Equivalence<span class="token operator">&lt;</span><span class="token operator">?</span> <span class="token keyword">super</span> V<span class="token operator">&gt;</span> valueEquivalence<span class="token punctuation">,</span>
    <span class="token comment">// key 只在左边 map 出现</span>
    Map<span class="token operator">&lt;</span>K<span class="token punctuation">,</span> V<span class="token operator">&gt;</span> onlyOnLeft<span class="token punctuation">,</span>
    <span class="token comment">// key 只在右边 map 出现，调用 doDifference 方法前已经包含了全部右边的值</span>
    Map<span class="token operator">&lt;</span>K<span class="token punctuation">,</span> V<span class="token operator">&gt;</span> onlyOnRight<span class="token punctuation">,</span>
    <span class="token comment">// key 在左右 map 中都出现过，并且 value 都相等</span>
    Map<span class="token operator">&lt;</span>K<span class="token punctuation">,</span> V<span class="token operator">&gt;</span> onBoth<span class="token punctuation">,</span>
    <span class="token comment">// key 在左右 map 中都出现过，但 value 不等</span>
    Map<span class="token operator">&lt;</span>K<span class="token punctuation">,</span> MapDifference<span class="token punctuation">.</span>ValueDifference<span class="token operator">&lt;</span>V<span class="token operator">&gt;&gt;</span> differences<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 以左边 map 为基准进行循环</span>
  <span class="token keyword">for</span> <span class="token punctuation">(</span>Entry<span class="token operator">&lt;</span><span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">K</span><span class="token punctuation">,</span> <span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">V</span><span class="token operator">&gt;</span> entry <span class="token operator">:</span> left<span class="token punctuation">.</span><span class="token function">entrySet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    K leftKey <span class="token operator">=</span> entry<span class="token punctuation">.</span><span class="token function">getKey</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    V leftValue <span class="token operator">=</span> entry<span class="token punctuation">.</span><span class="token function">getValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 右边 map 包含左边的 key</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>right<span class="token punctuation">.</span><span class="token function">containsKey</span><span class="token punctuation">(</span>leftKey<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// onlyOnRight 已经包含全部右边的值 所以需要删除当前 key</span>
      V rightValue <span class="token operator">=</span> onlyOnRight<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>leftKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token comment">// key 相等，并且 value 值也相等</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>valueEquivalence<span class="token punctuation">.</span><span class="token function">equivalent</span><span class="token punctuation">(</span>leftValue<span class="token punctuation">,</span> rightValue<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        onBoth<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>leftKey<span class="token punctuation">,</span> leftValue<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token comment">// key 相等，但 value 值不等</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        differences<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>leftKey<span class="token punctuation">,</span> ValueDifferenceImpl<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>leftValue<span class="token punctuation">,</span> rightValue<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token comment">// 右边 map 不包含左边的 key，就是左边 map 独有的 key</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      onlyOnLeft<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>leftKey<span class="token punctuation">,</span> leftValue<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">这是一种比较优秀的，快速比对的算法，可以好好看下上面的源码，然后把这种算法背下来，或者自己再次实现一次。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">Sets 的使用方式和 Lists 和 Maps 很类似，没有太大的亮点，我们就不说了。</p>
</div><div class="cl-preview-section"><h2 id="总结" style="font-size: 30px;">4 总结</h2>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">这一小节主要都是实战内容，在实际工作中可以用起来。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">在 Guava 对集合的设计中，有两个大点是非常值得我们学习的：</p>
</div><div class="cl-preview-section"><ol>
<li style="font-size: 20px; line-height: 38px;">Lists、Maps 的出现给我们提供了更方便的使用姿势和方法，我们在实际工作中，如果碰到特别繁琐，或者特别难用的 API，我们也可以进行一些包装，使更好用，这个是属于在解决目前的痛点的问题上进行创新，是非常值得提倡的一件事情，往往可以帮助你拿到更好的绩效。</li>
<li style="font-size: 20px; line-height: 38px;">如果有人问你，List 或者 Map 高效的差异排序算法，完全可以参考 Maps.difference 的内部实现，该方法只使用了一次循环，就可得到所有的相同或不同结果，这种算法在我们工作中也经常被使用。</li>
</ol>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">了解更多，可以直接前往 Guava 的代码库查看：<a href="https://github.com/google/guava">https://github.com/google/guava</a></p>
</div>}
                        </div>
                    </div>
                                            <!-- 买过的阅读 -->
                        <div class="art-next-prev clearfix">
                                                                                                <!-- 已买且开放 或者可以试读 -->
                                    <a href="/read/47/article/855">
                                                                    <div class="prev l clearfix">
                                        <div class="icon l">
                                            <i class="imv2-arrow3_l"></i>
                                        </div>
                                        <p>
                                            13 差异对比：集合在 Java 7 和 8 有何不同和改进
                                        </p>
                                    </div>
                                </a>
                                                                                                                            <!-- 已买且开放 或者可以试读 -->
                                    <a href="/read/47/article/857">
                                                                    <div class="next r clearfix">
                                        <p>
                                            15 CopyOnWriteArrayList 源码解析和设计思路
                                        </p>
                                        <div class="icon r">
                                            <i class="imv2-arrow3_r"></i>
                                        </div>

                                    </div>
                                </a>
                                                    </div>
                                    </div>
                <div class="comments-con js-comments-con" id="coments_con">
                </div>

                
            </div>
            
            
            

        </div>
    </div>
</div>

<div class="modal modal-jiaQun-new hide" id="modal-jiaQun">
    <div class="inner" style="">
        <div class="modal-close js-close-jiaQun">
            <i class="imv2-close"></i>
        </div>
        <div class="content">
            <img src="https://img4.mukewang.com/5d634d40000119e505400602.jpg">
            <div class="right-info">
                <div class="title">
                    扫码加入慕课Java核心用户群
                </div>
                <div class="desc">
                                            <p class="mb6">验证信息：<span id="joincode">1909271435058473</span><span class="copy js-copy-joincode">复制</span></p>
                                        <p class="mb6">QQ讨论群号：906691736</p>
                                            <p>QQ群URL：<a href="https://jq.qq.com/?_wv=1027&amp;k=55RtSbJ" target="_blank">点击访问</a></p>
                                    </div>
            </div>
            <p class="tip">若遇到搜索不到QQ群或加群失败，请联系客服邮箱:kf@imooc.com</p>
        </div>
    </div>
</div>
 
<!-- 专栏介绍页专栏评价 -->

<!-- 专栏介绍页底部三条评价 -->

<!-- 专栏阅读页弹层目录和介绍页页面目录 -->

<!-- 专栏阅读页发布回复 -->

<!-- 专栏阅读页发布评论 -->

<!-- 专栏阅读页底部评论 -->

<!-- 专栏阅读 单个 评论 -->

<!-- 新增回复和展开三条以外回复 -->

<!-- 立即订阅的弹窗 -->












</div></body></html>